package com.zy.runner;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.zy.annotation.RuleCmp;
import com.zy.bean.dto.BeanVarToJsonDto;
import com.zy.bean.po.RuleComponent;
import com.zy.enums.ReportTypeEnum;
import com.zy.scanning.RuleComponentRegister;
import com.zy.service.RuleComponentService;
import com.zy.util.SnowflakeIdWorker;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import static com.zy.util.BeanUtil.tranceVariableToJson;

/**
 * @author hanhuafeng
 * @version V1.0
 * @description
 * @date 2023/7/17
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class InitRunner implements ApplicationRunner {
    private final RuleComponentService ruleComponentService;
    private final ObjectMapper om = new ObjectMapper();

    @Override
    public void run(ApplicationArguments args) throws Exception {
        // 取出所有自动上报的所有组件
        List<RuleComponent> dbRuleComponents = ruleComponentService.listByReportType(ReportTypeEnum.AUTO);
        // 把RuleComponentRegister.FLOW_COMPONENT_MAP转换成Map<String, RuleCmp> flowCmpId -> RuleCmp
        Map<String, RuleCmp> flowCmpIdToRuleCmp = new LinkedHashMap<>(RuleComponentRegister.FLOW_COMPONENT_MAP.size());
        // 项目内部扫描到的组件id
        List<String> projectFlowCmpIdList = new LinkedList<>();
        for (RuleCmp ruleCmp : RuleComponentRegister.FLOW_COMPONENT_MAP.values()) {
            flowCmpIdToRuleCmp.put(ruleCmp.flowCmpId(), ruleCmp);
            projectFlowCmpIdList.add(ruleCmp.flowCmpId());
        }
        // 把库里面的组件转换成List<String> flowCmpId
        List<String> dbFlowCmpIdList = dbRuleComponents.stream().map(RuleComponent::getCmpId).toList();
        // 两个list碰撞，判断要新增和删除的组件
        // projectFlowCmpIdList有，dbFlowCmpIdList没有，说明要新增
        List<String> addFlowCmpIdList = new LinkedList<>(projectFlowCmpIdList);
        addFlowCmpIdList.removeAll(dbFlowCmpIdList);
        log.info("本次新增组件：{}", addFlowCmpIdList);
        log.info("共计新增组件：{}个", addFlowCmpIdList.size());
        // projectFlowCmpIdList没有，dbFlowCmpIdList有，说明要删除
        List<String> delFlowCmpIdList = new LinkedList<>(dbFlowCmpIdList);
        delFlowCmpIdList.removeAll(projectFlowCmpIdList);
        log.info("本次删除组件：{}", delFlowCmpIdList);
        log.info("共计删除组件：{}个", delFlowCmpIdList.size());
        // projectFlowCmpIdList有，dbFlowCmpIdList有，说明要更新
        List<String> updateFlowCmpIdList = new LinkedList<>(projectFlowCmpIdList);
        updateFlowCmpIdList.retainAll(dbFlowCmpIdList);
        log.info("本次更新组件：{}", updateFlowCmpIdList);
        log.info("共计更新组件：{}个", updateFlowCmpIdList.size());
        // 新增
        for (String addFlowCmpId : addFlowCmpIdList) {
            RuleCmp ruleCmp = flowCmpIdToRuleCmp.get(addFlowCmpId);
            RuleComponent ruleComponent = new RuleComponent();
            if (!ruleCmp.params().equals(Object.class)) {
                List<BeanVarToJsonDto> beanVarToJsonDtos = tranceVariableToJson(ruleCmp.params());
                ruleComponent.setParams(om.writeValueAsString(beanVarToJsonDtos));
            }
            ruleComponent.setCode(SnowflakeIdWorker.getUuid());
            ruleComponent.setCmpId(ruleCmp.flowCmpId());
            ruleComponent.setCmpType(ruleCmp.cmpType().name());
            ruleComponent.setDefaultText(ruleCmp.defaultText());
            ruleComponent.setReportType(ReportTypeEnum.AUTO.getCode());
            ruleComponentService.save(ruleComponent);
        }
        // 删除
        if (ObjectUtils.isNotEmpty(delFlowCmpIdList)) {
            ruleComponentService.lambdaUpdate()
                    .in(RuleComponent::getCmpId, delFlowCmpIdList)
                    .remove();
        }
        // 更新
        for (String updateFlowCmpId : updateFlowCmpIdList) {
            RuleCmp ruleCmp = flowCmpIdToRuleCmp.get(updateFlowCmpId);
            RuleComponent ruleComponent = new RuleComponent();
            if (!ruleCmp.params().equals(Object.class)) {
                List<BeanVarToJsonDto> beanVarToJsonDtos = tranceVariableToJson(ruleCmp.params());
                ruleComponent.setParams(om.writeValueAsString(beanVarToJsonDtos));
            }
            ruleComponent.setCmpId(ruleCmp.flowCmpId());
            ruleComponent.setCmpType(ruleCmp.cmpType().name());
            ruleComponent.setDefaultText(ruleCmp.defaultText());
            ruleComponentService.lambdaUpdate()
                    .eq(RuleComponent::getCmpId, ruleCmp.flowCmpId())
                    .eq(RuleComponent::getCmpType, ruleCmp.cmpType().name())
                    .update(ruleComponent);
        }
    }
}
